@node POSIX file system access
@section File system access

@stindex posix-files
These procedures operate on the file system via the facilities defined
by POSIX and offer more than standard & portable R5RS operations.  All
of these names are exported by the structures @code{posix-files} and
@code{posix}.

@cindex POSIX directory access
@cindex directory streams
@deffn procedure open-directory-stream filename @returns{} dir-stream
@deffnx procedure directory-stream? object @returns{} boolean
@deffnx procedure read-directory-stream dir-stream @returns{} filename or @code{#f}
@deffnx procedure close-directory-stream dir-stream @returns{} unspecified
Directory streams are the low-level interface provided by POSIX to
enumerate the contents of a directory.  @code{Open-directory-stream}
opens a new directory stream that will enumerate all of the files
within the directory named by @var{filename}.  @code{Directory-stream?}
is the disjoint type predicate for directory streams.
@code{Read-directory-stream} consumes the next filename from
@var{dir-stream} and returns it, or returns @code{#f} if the stream has
finished.  Note that @code{read-directory-stream} will return only
simple filenames, not full pathnames.  @code{Close-directory-stream}
closes @var{dir-stream}, removing any storage it required in the
operating system.  Closing an already closed directory stream has no
effect.
@end deffn

@cindex directory listing
@cindex listing directories
@deffn procedure list-directory filename @returns{} string list
Returns the list of filenames in the directory named by @var{filename}.
This is equivalent to opening a directory stream, repeatedly reading
from it & accumulating the list of filenames, and closing the stream.
@end deffn

@cindex POSIX working directory
@cindex working directory
@deffn procedure working-directory @returns{} string
@deffnx procedure set-working-directory! string @returns{} unspecified
These access the working directory's filename of the current process.
@end deffn

@cindex POSIX file opening
@deffn procedure open-file pathname file-options [file-mode] @returns{} port
Opens a port to the file named by the string @var{pathname}.
@var{File-options} specifies various aspects of the port.  The optional
@var{file-mode} argument is used only if the file to be opened does not
already exist; it specifies the permissions to be assigned to the file
if it is created.  The returned port is an input port if the given
options include @code{read-only}; otherwise @code{open-file} returns an
output port.  Because Scheme48 does not support combined input/output
ports, @code{dup-switching-mode} can be used to open an input port for
output ports opened with the @code{read-write} option.
@end deffn

File options are stored in a boxed mask representation.  File option
sets are created with @code{file-options} and tested with
@code{file-options-on?}.

@deffn syntax file-options name @dots{} @returns{} file-options
@deffnx procedure file-options-on? options@suba{a} options@suba{b} @returns{} boolean
@code{File-options} evaluates to a file option set, suitable for passing
to @code{open-file}, that includes all of the given named options.
@code{File-options-on?} returns true if @var{options@suba{a}} includes
all of the options in @var{options@suba{b}}, or false if otherwise.

The following file option names are supported as arguments to the
@code{file-options} syntax:

@table @code
@item create
create file if it does not already exist; a @var{file-mode} argument is
required to be passed to @code{open-file} if the @code{create} option
is specified

@item exclusive
an error will be signalled if this option & @code{create} are both set
and the file already exists

@item no-controlling-tty
if the pathname being opened is a terminal device, the terminal will
not become the controlling terminal of the process

@item truncate
file is truncated

@item append
written data to the newly opened file will be appended to the existing
contents

@item nonblocking
read & write operations will not block

@item read-only
file may not be written to, only read from

@item read-write
file may be both read from & written to

@item write-only
file may not be read from, only written to
@end table

The last three are all mutually exclusive.
@end deffn

Examples:

@lisp
(open-file "some-file.txt"
           (file-options create write-only)
           (file-mode read owner-write))@end lisp

@noindent
returns an output port that writes to a newly-created file that can be
read from by anyone but written to only by the owner.  Once the file
@file{some-file.txt} exists,

@lisp
(open-file "some-file.txt"
           (file-options append write-only))@end lisp

@noindent
will open an output port that appends to the file.

@embedref{POSIX I/O utilities,@code{I/o-flags} & @code{set-i/o-flags!}}
can be used to access the @code{append}, @code{nonblocking}, and
read/write file options of ports, as well as modify the @code{append} &
@code{nonblocking} options.

@cindex nonblocking I/O
@cindex blocking I/O
To keep port operations from blocking in the Scheme48 process, output
ports are set to be nonblocking at the time of creation.  (Input ports
are managed using @code{select(2)}.)  @code{Set-i/o-flags!} can be used
to make an output port blocking, for example directly before forking,
but care should be exercised, because the Scheme48 run-time system may
be confused if an I/O operation blocks.

@cindex POSIX file creation masks
@deffn procedure set-file-creation-mask! file-mode @returns{} file-mode
Sets the file creation mask to be @var{file-mode}.  Bits set in
@var{file-mode} are cleared in the modes of any files or directories
subsequently created by the current process.
@end deffn

@cindex POSIX links
@cindex creating POSIX links
@cindex creating directories
@cindex making directories
@cindex directory creation
@cindex POSIX FIFOs
@cindex creating POSIX FIFOs
@deffn procedure link existing-pathname new-pathname @returns{} unspecified
@deffnx procedure make-directory pathname file-mode @returns{} unspecified
@deffnx procedure make-fifo pathname file-mode @returns{} unspecified
@code{Link} creates a hard link for the file at @var{existing-pathname}
at @var{new-pathname}.  @code{Make-directory} creates a new directory
at the locations specified by @var{pathname} with the the file mode
@var{file-mode}.  @code{Make-fifo} does similarly, but it creates a
FIFO (first-in first-out) file instead of a directory.
@end deffn

@cindex deleting files
@cindex file deletion
@cindex removing files
@cindex deleting directories
@cindex directory deletion
@cindex removing directories
@cindex renaming files
@deffn procedure unlink pathname @returns{} unspecified
@deffnx procedure remove-directory pathname @returns{} unspecified
@deffnx procedure rename old-pathname new-pathname @returns{} unspecified
@code{Unlink} removes a link at the location @var{pathname}.
@code{Remove-directory} removes a directory at the location specified
by @var{pathname}.  The directory must be empty; an exception is
signalled if it is not.  @code{Rename} moves the file at the location
@var{old-pathname} to the new location @var{new-pathname}.
@end deffn

@cindex file access probing
@deffn procedure accessible? pathname access-mode more-modes @dots{} @returns{} boolean
@deffnx syntax access-mode name @returns{} access mode
@code{Accessible?} returns true if @var{pathname} is accessible by all
of the given access modes.  (There must be at least one access mode
argument.)  @code{Access-mode} evaluates to an access mode, suitable for
passing to @code{accessible?}, from the given name.  The allowed names
are @code{read}, @code{write}, @code{execute}, & @code{exists}.
@end deffn

@cindex file info
Information about files can be queried using the @dfn{file info}
abstraction.  Every file has a corresponding file info record, which
contains various data about the file including its name, its type,
its device & inode numbers, the number of links to it, its size in
bytes, its owner, its group, its file mode, and its access times.

@deffn procedure get-file-info pathname @returns{} file-info
@deffnx procedure get-file/link-info pathname @returns{} file-info
@deffnx procedure get-port-info fd-port @returns{} file-info
@code{Get-file-info} & @code{get-file/link-info} return a file info
record for the files named by @var{pathname}.  @code{Get-file-info}
follows symbolic links, however, while @code{get-file/link} info does
not.  @code{Get-port-info} returns a file info record for the file that
@var{fd-port} is a port atop a file descriptor for.  If @var{fd-port}
does not read from or write to a file descriptor, an error is
signalled.
@end deffn

@deffn procedure file-info? object @returns{} boolean
@deffnx procedure file-info-name file-info @returns{} string
@deffnx procedure file-info-device file-info @returns{} integer
@deffnx procedure file-info-inode file-info @returns{} integer
@deffnx procedure file-info-link-count file-info @returns{} integer
@deffnx procedure file-info-size file-info @returns{} integer
@deffnx procedure file-info-owner file-info @returns{} user-id
@deffnx procedure file-info-group file-info @returns{} group-id
@deffnx procedure file-info-mode file-info @returns{} file-mode
@deffnx procedure file-info-last-access file-info @returns{} time
@deffnx procedure file-info-last-modification file-info @returns{} time
@deffnx procedure file-info-last-change file-info @returns{} time
Accessors for various file info record fields.  The name is the string
passed to @code{get-file-info} or @code{get-file/link-info}, if the
file info record was created with either of those two, or the name of
the file that the file descriptor of the port queried was created on,
if the file info record was obtained with @code{get-port-info}.
@end deffn

@deffn procedure file-info-type file-info @returns{} file-type
@deffnx syntax file-type name @returns{} file-type
@deffnx procedure file-type? object @returns{} boolean
@deffnx procedure file-type-name file-type @returns{} symbol
@code{File-info-type} returns the type of the file as a @dfn{file type}
object.  File types may be compared using @code{eq?}.  @code{File-type}
evaluates to a file type of the given name.  The disjoint type predicate
for file types is @code{file-type?}.  @code{File-type-name} returns the
symbolic name that represents @var{file-type}.

The valid file type names are:

@itemize @w{}
@item @code{regular}
@item @code{directory}
@item @code{character-device}
@item @code{block-device}
@item @code{fifo}
@item @code{symbolic-link} (not required by POSIX)
@item @code{socket} (not required by POSIX)
@item @code{other}
@end itemize
@end deffn

@cindex POSIX file permissions
@cindex file permissions
@dfn{File modes} are boxed integers that represent POSIX file
protection masks.

@deffn syntax file-mode permission-name @dots{} @returns{} file-mode
@deffnx procedure file-mode? object @returns{} boolean
@code{File-mode} evaluates to a file mode object that contains all of
the specified permissions.  @code{File-mode?} is the disjoint type
predicate for file mode descriptor objects.  These are all of the names,
with their corresponding octal bit masks and meanings, allowed to be
passed to @code{file-mode}:

@multitable {Permission name} {Octal mask} {execute (or search) by others}
@item Permission name @tab Octal mask @tab Description
@item @code{set-uid}     @tab @code{#o4000} @tab set user id when executing
@item @code{set-gid}     @tab @code{#o2000} @tab set group id when executing
@item @code{owner-read}  @tab @code{#o0400} @tab read by owner
@item @code{owner-write} @tab @code{#o0200} @tab write by owner
@item @code{owner-exec}  @tab @code{#o0100} @tab execute (or search) by owner
@item @code{group-read}  @tab @code{#o0040} @tab read by group
@item @code{group-write} @tab @code{#o0020} @tab write by group
@item @code{group-exec}  @tab @code{#o0010} @tab execute (or search) by group
@item @code{other-read}  @tab @code{#o0004} @tab read by others
@item @code{other-write} @tab @code{#o0002} @tab write by others
@item @code{other-exec}  @tab @code{#o0001} @tab execute (or search) by others
@end multitable

Also, several compound masks are supported for convenience:

@multitable {Permission set name} {Octal mask} {read, write, & execute by anyone}
@item Permission set name @tab Octal mask @tab Description
@item @code{owner} @tab @code{#o0700} @tab read, write, & execute by owner
@item @code{group} @tab @code{#o0070} @tab read, write, & execute by group
@item @code{other} @tab @code{#o0007} @tab read, write, & execute by others
@item @code{read}  @tab @code{#o0444} @tab read by anyone
@item @code{write} @tab @code{#o0111} @tab write by anyone
@item @code{exec}  @tab @code{#o0777} @tab read, write, & execute by anyone
@end multitable
@end deffn

@deffn procedure file-mode+ file-mode @dots{} @returns{} file-mode
@deffnx procedure file-mode- file-mode@suba{a} file-mode@suba{b} @returns{} file-mode
@deffnx procedure file-mode=? file-mode@suba{a} file-mode@suba{b} @returns{} boolean
@deffnx procedure file-mode<=? file-mode@suba{a} file-mode@suba{b} @returns{} boolean
@deffnx procedure file-mode>=? file-mode@suba{a} file-mode@suba{b} @returns{} boolean
@code{File-mode+} returns a file mode that contains all of the
permissions specified in any of its arguments.  @code{File-mode-}
returns a file mode that contains all of @var{file-mode@suba{a}}'s
permissions not in @var{file-mode@suba{b}}.  @code{File-mode=?} tests
whether two file modes are the same.  @code{File-mode<=?} returns true
if each successive file mode argument has the same or more permissions
as the previous one.  @code{File-mode>=?} returns true if each
successive file mode argument has the same or fewer permissions as the
previous one.
@end deffn

@deffn procedure file-mode->integer file-mode @returns{} integer
@deffnx procedure integer->file-mode integer @returns{} file-mode
These convert between file mode objects and Unix file mode masks as
integers.  The integer representations may or may not be the masks used
by the underlying operating system.
@end deffn
